package persistencia;

import java.io.IOException;
import java.util.ArrayList;

import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import bean.Behaviour;
import bean.InputOutputFault;
import bean.PEWSOperation;
import bean.PEWSOperations;
import bean.PortType;
import bean.Schema;
import bean.WSDLOperation;

/**
 * Classe que extrai dados dos arquivos xpews e wsdl, e coloca-os em seus respctivos objetos
 * 
 */

public class Parse {
	Extrator extrator;
	PEWSOperations pewsOperations;
	Behaviour behaviour;
	PortType portType;
	Schema schema;
	
	public Parse() {
		extrator = new Extrator();
		pewsOperations = new PEWSOperations();
		behaviour = new Behaviour();
		portType = new PortType();
		schema = new Schema();
	}
	
	public Parse(String arquivo) throws ParserConfigurationException, SAXException, IOException{
		extrator = new Extrator(arquivo);
		verificarArquivo(arquivo);
	}
	
	/** Depois muda isso */
	private void verificarArquivo(String arquivo){
		if(arquivo.endsWith(".xml")){
			pewsOperations = new PEWSOperations();
			behaviour = new Behaviour();
			xpewsParsePEWSOperations();
		}
		else{
			portType = new PortType();
			wsdlParsePortType();
		}
			
	}
	
	// Parse XPEWS
	
	/** Extrai o arquivo xpews e atribui esses valores em um objeto "PEWSOperations" */
	private void xpewsParsePEWSOperations(){
		Node operationsNode = extrator.buscarTagPorNome("operations");
		
		xpewsParseBehaviour();
		pewsOperations.setPewsOperations((xpewsParsePEWSOperation(operationsNode.getChildNodes())));
	}
	
	/** Retorna um ArrayList de PEWSOperation,
	 onde cada item do ArrayList é um nó "operation" no arquivo XPEWS. */
	private ArrayList<PEWSOperation> xpewsParsePEWSOperation(NodeList operationsNodeList){
		ArrayList<PEWSOperation> pewsOps = new ArrayList<PEWSOperation>();
		
		for(int i = 0; i < operationsNodeList.getLength(); i++){
			if(operationsNodeList.item(i).getNodeType() == Node.ELEMENT_NODE){
				PEWSOperation pews = new PEWSOperation();
				pews.setName(operationsNodeList.item(i).getAttributes().item(0).getNodeValue());
				String ns = operationsNodeList.item(i).getAttributes().item(2).getNodeValue();
				pews.setNs(ns.substring(0, ns.indexOf(":")));
				pewsOps.add(pews);
			}
		}
		
		return pewsOps;
	}
	
	/** Extrai o arquivo xpews e atribui esses valores em um objeto "Behaviour" */
	private void xpewsParseBehaviour(){
		Node behaviourNode = extrator.buscarTagPorNome("behaviour");
		
		behaviour.setName(behaviourNode.getAttributes().item(0).getNodeValue());
		for(int i = 1; i < behaviourNode.getAttributes().getLength(); i++){
			String ns = behaviourNode.getAttributes().item(i).getNodeName();
			behaviour.getNs().add(ns.substring(ns.indexOf(":") + 1 , ns.length()));
			behaviour.getLinkNs().add(behaviourNode.getAttributes().item(i).getNodeValue());
		}
	}
	
	// Parse WSDL
	
	/** Extrai o arquivo wsdl e atribui esses valores em um objeto "PortType" */
	private void wsdlParsePortType(){
		Node portTypeNode = extrator.buscarTagPorNome("wsdl:portType");
		
		if(portTypeNode == null)
			portTypeNode = extrator.buscarTagPorNome("portType");
			
		portType.setName(portTypeNode.getAttributes().item(0).getNodeValue());
		portType.setOperation(wsdlParseWSDLOperations(portTypeNode.getChildNodes()));
	}
	
	/** Retorna um objeto ArrayList de Operations,
	 onde cada item do ArrayList é um nó "wsdl:operation" */
	private ArrayList<WSDLOperation> wsdlParseWSDLOperations(NodeList opertationsNodeList){
		ArrayList<WSDLOperation> operations = new ArrayList<WSDLOperation>();
		
		for(int i = 0; i < opertationsNodeList.getLength(); i++){
			if(opertationsNodeList.item(i).getNodeType() == Node.ELEMENT_NODE){
				WSDLOperation operation = new WSDLOperation();
				operation.setName(opertationsNodeList.item(i).getAttributes().item(0).getNodeValue());
				operation.setInput(wsdlParseinputOutputFault(opertationsNodeList.item(i).getChildNodes(), 0));
				operation.setOutput(wsdlParseinputOutputFault(opertationsNodeList.item(i).getChildNodes(), 2));
				operations.add(operation);
			}
		}
		return operations;
	}
	
	/** Retorna um objeto "InputOutputFault" podendo este ser um dos 3 (input, output, fault) */
	private InputOutputFault wsdlParseinputOutputFault(NodeList operationNodeList, int i){
		InputOutputFault iOF = new InputOutputFault();
		
		if(operationNodeList.item(i).getNodeType() == Node.ELEMENT_NODE && operationNodeList.item(i).hasAttributes()){
			iOF.setMessage(operationNodeList.item(i).getAttributes().item(0).getNodeValue());
			iOF.setName(operationNodeList.item(i).getAttributes().item(1).getNodeValue());
		}
		
		return iOF;
	}
	
	public Extrator getExtrator() {
		return extrator;
	}

	public void setExtrator(Extrator extrator) {
		this.extrator = extrator;
	}
	
	/** Atribui um arquivo xpews e é feita sua extração */
	public void setArquivoXPEWS(String arquivo){
		extrator.setArquivoXML(arquivo);
		xpewsParsePEWSOperations();
	}
	
	/** Atribui um arquivo wsdl e é feita sua extração */
	public void setArquivoWSDL(String arquivo){
		extrator.setArquivoXML(arquivo);
		wsdlParsePortType();
	}

	/** Retorna um objeto "PEWSOperations" */
	public PEWSOperations getPewsOperations() {
		return pewsOperations;
	}

	public void setPewsOperations(PEWSOperations pewsOperations) {
		this.pewsOperations = pewsOperations;
	}
	
	/** Retorna um objeto "Behaviour" */
	public Behaviour getBehaviour() {
		return behaviour;
	}

	public void setBehaviour(Behaviour behaviour) {
		this.behaviour = behaviour;
	}

	/** Retorna um objeto "PortType" */
	public PortType getPortType() {
		return portType;
	}

	public void setPortType(PortType portType) {
		this.portType = portType;
	}
	
	public void wsdlParseSchema(){
		Node schemaNode = extrator.buscarTagPorNome("xs:schema");
		
		/*for(int i = 0; i < schemaNode.getAttributes().getLength(); i++){
			if(schemaNode.getAttributes().item(i).getNodeName().equalsIgnoreCase("xmlnsXS"))
				schema.setXmlnsXS(schemaNode.getAttributes().getNamedItem("xmlnsXS").getNodeValue());
			if(schemaNode.getAttributes().item(i).getNodeName().equalsIgnoreCase("targetNamespace"))
				schema.setTargetNamespace(schemaNode.getAttributes().getNamedItem("targetNamespace").getNodeValue());
			if(schemaNode.getAttributes().item(i).getNodeName().equalsIgnoreCase("elementFormDefault"))
				schema.setElementFormDefault(schemaNode.getAttributes().getNamedItem("elementFormDefault").getNodeValue());
			if(schemaNode.getAttributes().item(i).getNodeName().equalsIgnoreCase("attributeFormDefault"))
				schema.setAttributeFormDefault(schemaNode.getAttributes().getNamedItem("attributeFormDefault").getNodeValue());
		}*/
	}
}	